#include "md5.h"
#include <stdlib.h>
#include <iostream>
using namespace std;
unsigned int shl(unsigned int a, unsigned int s)
{
    return ((a<<s)|(a>>(32-s)));
}
int CalMD5(char * addr, int size){
	int size_of_last_block = size % SIZE_OF_BLOCK;
	int number_of_zero_bytes;
	char *buf = (char*)malloc(size+60);
	if(size_of_last_block < 56)number_of_zero_bytes = 56 - size_of_last_block;
	else
		number_of_zero_bytes = SIZE_OF_BLOCK - size_of_last_block + 56;
	long number_of_blocks = (size + number_of_zero_bytes+ 8)/ SIZE_OF_BLOCK;
	buf+=size;
	*buf = 0x80;
	long num_of_blocks = (size + number_of_zero_bytes + 8) / SIZE_OF_BLOCK;
	if(number_of_zero_bytes-1>0){
		for(int i = 0; i< number_of_zero_bytes -1; i++){
			*(buf)=0;
			buf++;	
		}
	}
	long long bit_file_size = size *8;
	char bb[8];
	for(int i =0; i< 8; i++){
		*buf = bit_file_size & 0xff;
		bit_file_size /= 256;
		buf++;
	}
	 unsigned int s[64] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
                 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20, 5,  9, 14, 20,
                 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
                 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};

    //Use binary integer part of the sines of integers (Radians) as constants:
    //(Or just use the following table):
    unsigned int k[64] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee ,
                 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 ,
                 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be ,
                 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 ,
                 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa ,
                 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 ,
                 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed ,
                 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a ,
                 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c ,
                 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 ,
                 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 ,
                 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 ,
                 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 ,
                 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 ,
                 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 ,
                 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };

    //Initialize variables:
     unsigned int h0 = 0x67452301;   //A
     unsigned int h1 = 0xefcdab89;   //B
     unsigned int h2 = 0x98badcfe;   //C
     unsigned int h3 = 0x10325476;   //D

	 unsigned int w[16], f, g, a, b, c, d, temp;
	 unsigned int * pint = (unsigned int *)buf;

	  for(int i = 0 ; i < num_of_blocks; i++)
     {
         for(int j = 0; j < 16; j++){
			 w[j] = *pint;
			 pint++;
		 }
        //Initialize hash value for this chunk:
        a = h0;
        b = h1;
        c = h2;
        d = h3;
        //Main loop:
        for(int i = 0; i < 64; i++)
        {
            if (i >= 0 && i <= 15)
            {
                f = (b & c) | ((~ b) & d);
                g = i;
            }
            else if (i >= 16 && i <= 31)
            {
                f = (d & b) | ((~ d) & c);
                g = (5*i + 1)%16;
            }
            else if (i >= 32 && i <= 47)
            {
                f = b ^ c ^ d;
                g = (3*i + 5)%16;
            }
            else if (i >= 48 && i <= 63)
            {
                f = c ^ (b | (~ d));
                g = (7*i)%16;
            }
            temp = d;
            d = c;
            c = b;
            b = b + shl(a + f + k[i] + w[g], s[i]);
            a = temp;
        }
        //Add this chunk's hash to result so far:
        h0 = h0 + a;
        h1 = h1 + b;
        h2 = h2 + c;
        h3 = h3 + d;
     }

	  cout << "MD5 = " << hex << h0<< " " << hex << h1<< " " << hex << h2 << " " << hex << h3<< endl;
    return 0;
}